﻿using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 综合同步
{
    public class RedisExchange
    {
        const int redisFileNameLength = 512;
        int m_redisPort = 6379;
        string m_redisIP;
        string m_redisPassword;
        bool m_bStop = false;

        ConnectionMultiplexer m_connect;
        public bool Connected { get { return m_connect?.IsConnected??false; } }
        EndPoint[] EndPoints { get { return m_connect?.GetEndPoints(); } }
        public IDatabase DataBase { get { return m_connect?.GetDatabase(); } }
        IServer GetServer { get { return m_connect?.GetServer(m_redisIP, m_redisPort); } }

        public RedisExchange(string ip, ushort port, string password = "")
        {
            try
            {
                m_redisIP = ip;
                m_redisPort = port;
                m_redisPassword = password;
                StringWriter sw = new StringWriter();
                m_connect = ConnectionMultiplexer.Connect(ip + ":" + port +
                    (string.IsNullOrEmpty(password) ? "" : ",password=" + password), sw);
                FileLogOperator.Info("Redis启动成功");
            }
            catch (Exception eRedis)
            {
                FileLogOperator.Error("Redis启动失败：" + eRedis.Message);
            }
            //启动检查
            Task.Run(new Action(() =>
            {
                while (!m_bStop)
                {
                    try
                    {
                        if (m_connect == null || !m_connect.IsConnected)
                            m_connect = ConnectionMultiplexer.Connect(m_redisIP + ":" + m_redisPort +
                                (string.IsNullOrEmpty(m_redisPassword) ? "" : ",password=" + m_redisPassword));
                    }
                    catch (Exception eRedis) {
                        FileLogOperator.Error("Redis连接失败：" + eRedis.Message);
                    }
                    Thread.Sleep(3000);
                }
            }));
        }
        ~RedisExchange()
        {
            m_bStop = true;
        }
        public long ListLength(string key){ 
            try{
                return Connected?(DataBase?.ListLength(key)??0):0;
            }catch{return 0;}
        }
        public byte[][] ListRange(string key,int start,int end){ 
            try{
                return Connected?DataBase?.ListRange(key,start,end).Cast<byte[]>().ToArray():null;
            }catch{return null;}
        }
        public byte[] ListGetByIndex(string key,long index){ 
            try{
                return Connected?DataBase?.ListGetByIndex(key,index):null;
            }catch{return null;}
        }
        public void SetData(string key,byte[] value) { 
            try{
                if(Connected)
                    DataBase?.ListRightPush(key, value);
            }catch{return;}
        }
        public byte[] GetData(string key) {
            try{
                return Connected?DataBase?.ListLeftPop(key):null;
            }catch{return null;}
        }
        public byte[] LastData(string key){
            try{
                return Connected?DataBase?.ListRange(key,-1).FirstOrDefault():null;
            }catch{return null;}
        }
        public bool SaveFile(string key, string filename)
        {
            try
            {
                using (Stream file = File.OpenRead(filename))
                {
                    byte[] fileBytes = Encoding.Default.GetBytes(filename);
                    if (fileBytes.Length > redisFileNameLength)
                        fileBytes = fileBytes.Take(redisFileNameLength).ToArray();
                    else if (fileBytes.Length < redisFileNameLength)
                        fileBytes = fileBytes.Concat(new byte[redisFileNameLength - fileBytes.Length]).ToArray();
                    BinaryReader reader = new BinaryReader(file, Encoding.Default);
                    if (file.Length > int.MaxValue)
                        FileLogOperator.Error(filename + ":超过最大文件值，" + file.Length);
                    SetData(key, fileBytes.Concat(reader.ReadBytes((int)file.Length)).ToArray());
                    reader.Close();
                    return true;
                }
            }
            catch(Exception ex) {
                FileLogOperator.Error(ex.Message);
                return false;
            }
        }
        public bool GetFile(string key,string path)
        {
            try
            {
                byte[] fileStreamData = GetData(key);
                if (fileStreamData == null) return false;
                string redisSavePath = Encoding.Default.GetString(fileStreamData,0,redisFileNameLength);
                File.WriteAllBytes(Path.Combine(path,redisSavePath),
                    fileStreamData.Skip(redisFileNameLength).ToArray());
                return true;
            }
            catch (Exception ex)
            {
                FileLogOperator.Error(ex.Message);
                return false;
            }
        }
        public bool Remove(string key) { 
            try{
                return Connected?(DataBase?.KeyDelete(key)??false):false; 
            }catch{return false;}
        }
        public bool Exists(string key) { 
            try{
                return Connected?(DataBase?.KeyExists(key)??false):false; 
            }catch{return false;}
        }
        public long Publish(string channel, string message)
        {
            ISubscriber sub = m_connect.GetSubscriber();
            return sub.Publish(channel, message);
        }
        public void Subscribe(string channelFrom)
        {
            ISubscriber sub = m_connect.GetSubscriber();
            sub.Subscribe(channelFrom);
        }
    }
}
